﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace TuxedoLib
{
	internal class GameWindow : Window
	{
		private TuxedoApp app;

		private uint[] screenPixels;
		private int pixelWidth;
		private int pixelHeight;
		private string title;

		private List<Event> events = new List<Event>();
		private PressedKeysLookup pressedKeys = new PressedKeysLookup();

		public GameWindow(int width, int height, string title, int targetFps, TuxedoApp app)
		{
			this.pixelWidth = width;
			this.pixelHeight = height;

			this.title = title;
			this.Title = title;
			this.Width = width;
			this.Height = height;
			this.app = app;

			this.screenPixels = new uint[width * height];

			this.Loaded += (sender, e) =>
			{
				this.InitializeUI(width, height);

				Image screen = new Image(width, height);

				System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
				int milliseconds = 1000 / targetFps;
				timer.Interval = new System.TimeSpan(0, 0, 0, 0, milliseconds);
				timer.Tick += (tsender, te) =>
				{
					long begin = DateTime.Now.Ticks;
					app.DoUpdate(this.events.ToArray(), this.pressedKeys);
					this.events.Clear();
					app.DoRender(screen);

					this.SyncScreen(screen);
					long end = DateTime.Now.Ticks;

					double diff = (end - begin) / 10000000.0;

					double fpsTimesTen = diff == 0 ? 99999 : 10 / diff;

					double fps = ((int)fpsTimesTen) / 10.0;

					if (fps > 60)
					{
						this.Title = "[60+ FPS] " + this.title;
					}
					else
					{
						this.Title = "[" + fps + " FPS] " + this.title;
					}
				};
				timer.Start();
			};
		}

		private void SyncScreen(Image screenImage)
		{
			this.screenBmp.Lock();
			this.screenBmp.WritePixels(new Int32Rect(0, 0, this.pixelWidth, this.pixelHeight), screenImage.pixels, 4 * this.pixelWidth, 0);
			this.screenBmp.Unlock();
		}

		private WriteableBitmap screenBmp;

		private long previousFrameTimestamp = DateTime.Now.Ticks;

		private void InitializeUI(int width, int height)
		{
			WriteableBitmap wbmp = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
			System.Windows.Controls.Image screenImage = new System.Windows.Controls.Image() { Source = wbmp, HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, Stretch = Stretch.Fill };
			Grid clickCatcher = new Grid() { Background = Brushes.Transparent, HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch };
			Grid uiHost = new Grid() { Background = Brushes.Black, HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch };

			uiHost.Children.Add(screenImage);
			uiHost.Children.Add(clickCatcher);
			
			clickCatcher.MouseDown += this.clickCatcher_MouseDown;
			clickCatcher.MouseUp += this.clickCatcher_MouseUp;
			clickCatcher.MouseMove += this.clickCatcher_MouseMove;

			this.KeyDown += (sender, e) => { this.HandleKey(e, true); };
			this.KeyUp += (sender, e) => { this.HandleKey(e, false); };

			this.Content = uiHost;
			this.screenBmp = wbmp;
		}

		private static readonly Dictionary<System.Windows.Input.Key, Key> KEY_CONVERTER = new Dictionary<System.Windows.Input.Key, Key>()
		{
			{ System.Windows.Input.Key.Up, Key.Up },
			{ System.Windows.Input.Key.Down, Key.Down },
			{ System.Windows.Input.Key.Left, Key.Left },
			{ System.Windows.Input.Key.Right, Key.Right },

			{ System.Windows.Input.Key.Enter, Key.Enter },
			{ System.Windows.Input.Key.Space, Key.Space },
			{ System.Windows.Input.Key.Tab, Key.Tab },
			// uhhh...backspace?

			{ System.Windows.Input.Key.Insert, Key.Insert },
			{ System.Windows.Input.Key.Delete, Key.Delete },
			{ System.Windows.Input.Key.Home, Key.Home },
			{ System.Windows.Input.Key.End, Key.End },
			{ System.Windows.Input.Key.PageUp, Key.PageUp },
			{ System.Windows.Input.Key.PageDown, Key.PageDown },
			
			{ System.Windows.Input.Key.A, Key.A },
			{ System.Windows.Input.Key.B, Key.B },
			{ System.Windows.Input.Key.C, Key.C },
			{ System.Windows.Input.Key.D, Key.D },
			{ System.Windows.Input.Key.E, Key.E },
			{ System.Windows.Input.Key.F, Key.F },
			{ System.Windows.Input.Key.G, Key.G },
			{ System.Windows.Input.Key.H, Key.H },
			{ System.Windows.Input.Key.I, Key.I },
			{ System.Windows.Input.Key.J, Key.J },
			{ System.Windows.Input.Key.K, Key.K },
			{ System.Windows.Input.Key.L, Key.L },
			{ System.Windows.Input.Key.M, Key.M },
			{ System.Windows.Input.Key.N, Key.N },
			{ System.Windows.Input.Key.O, Key.O },
			{ System.Windows.Input.Key.P, Key.P },
			{ System.Windows.Input.Key.Q, Key.Q },
			{ System.Windows.Input.Key.R, Key.R },
			{ System.Windows.Input.Key.S, Key.S },
			{ System.Windows.Input.Key.T, Key.T },
			{ System.Windows.Input.Key.U, Key.U },
			{ System.Windows.Input.Key.V, Key.V },
			{ System.Windows.Input.Key.W, Key.W },
			{ System.Windows.Input.Key.X, Key.X },
			{ System.Windows.Input.Key.Y, Key.Y },
			{ System.Windows.Input.Key.Z, Key.Z },
			
			{ System.Windows.Input.Key.D0, Key.Num0 },
			{ System.Windows.Input.Key.D1, Key.Num1 },
			{ System.Windows.Input.Key.D2, Key.Num2 },
			{ System.Windows.Input.Key.D3, Key.Num3 },
			{ System.Windows.Input.Key.D4, Key.Num4 },
			{ System.Windows.Input.Key.D5, Key.Num5 },
			{ System.Windows.Input.Key.D6, Key.Num6 },
			{ System.Windows.Input.Key.D7, Key.Num7 },
			{ System.Windows.Input.Key.D8, Key.Num8 },
			{ System.Windows.Input.Key.D9, Key.Num9 },
		};

		private Key GetKey(System.Windows.Input.Key winKey)
		{
			Key output;
			if (KEY_CONVERTER.TryGetValue(winKey, out output))
			{
				return output;
			}

			return Key.Unknown;
		}

		private void HandleKey(System.Windows.Input.KeyEventArgs e, bool down)
		{
			Key key = GetKey(e.Key);
			if (key != Key.Unknown)
			{
				if (down && this.pressedKeys[key]) { return; } // Multiple firings because it thinks I'm typing.

				this.events.Add(new Event() { Type = EventType.Key, IsPress = down, Key = key });
				this.pressedKeys[key] = down;
			}
		}

		private void clickCatcher_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
		{
			
		}

		private void clickCatcher_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			
		}

		private void clickCatcher_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			
		}
	}
}
